perm filename 4RADD.OLD[HAL,HE] blob sn#116207 filedate 1974-08-20 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00011 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002		This file holds new, untried sections for 4R.DOC.
C00003 00003	 CONTROL STRUCTURES  now in memo
C00007 00004		PROCEDURES now in memo
C00013 00005	CONSTANT VELOCITY MOTION now in memo
C00015 00006		LIBRARY ROUTINES now in memo
C00022 00007		IMPLEMENTATION OF ON-MONITORS
C00025 00008		INTERPRETER CODE FOR MOTIONS
C00027 00009		THE INTERPRETER SCHEDULER
C00036 00010	DEPROACHES  now in memo
C00044 00011	SYSTEM USER FEATURES
C00053 ENDMK
C⊗;
	This file holds new, untried sections for 4R.DOC.
The oontents are open for discussion.

 CONTROL STRUCTURES  now in memo
	PROCEDURES now in memo
CONSTANT VELOCITY MOTION now in memo
	LIBRARY ROUTINES now in memo
	IMPLEMENTATION OF ON-MONITORS
This page is a set of notes for the eventual documentation.
Author:  RF

	The code for an on-monitor is in-line and jumped around.
The code is PDP11 code, including calls on arithmetic subroutines,
if neccessary.

Each on-monitor is given a unique name by the compiler.
The scheduler associates that name with the location of the
enable bit for this monitor.

On-monitors have only two states:  enabled and disabled.
There is a status word associated with each on-monitor;
it contains two bits:  the enabled, and the kill.

At the start of a program, all on-monitors are disabled.
That means enable=0, kill=0.

At the end of a block, the compiler includes code to disable all
on-monitors within that block.

Only one copy of an on-monitor ever exists.  No multiple instantiations.

ENABLE <NAME>
To enable a software monitor, 
tell kernel to activate it at its address, in on-level, where
it will have PDP11 code to:
1) look at its "enabled bit".  If already on, dismiss. If not, turn on.
2) clear all its working buffers (if any) 
3) schedule its second entry (the monitor itself) to be awakened at
the appropriate intervals.  Then dismiss.

The software monitor, every time it is awakened, does the following:
1)  look at its "kill bit".  If on, clear and dismiss.
2)  execute the code for its check.
3)  if condition satisfied, do immediate stuff,
 instantiate the conclusion, and dismiss.
4)  reschedule self at appropriate interval.  Dismiss.

To enable a hardware monitor,
tell kernel to activate it at its address, in on-level, where
it will have PDP11 code to:
1)  look at the device enabled bit.  If already on, return.  If not, turn on.
2)  dismiss.

DISABLE <NAME>
To disable a software monitor, set its  "kill bit".
To disable a hardware monitor, clear its "enabled bit".
	INTERPRETER CODE FOR MOTIONS
not yet ready.  Author:  RF.

The code generated for a move includes the following interpreter commands:

1) Prepare move.  This points to the move table, and causes the trajectory
to be modified to conform to current locations of via points.  Joint
loading is calculated for each via point as well.

2) Enable on-monitor.  There may be more than one of these instructions.

3) Start motion.  This points to the modified move table.

4) Await completion.  This causes the interpreter to wait until the
move has completed, or the arm has been stopped for some reason.
The signal which awakes the interpreter comes from whichever joint
servo finishes last: each servo, as it finishes, checks to see if all
the others are done, and if so, awakes the interpreter at servo level.

5) disable all on-monitors associated with move.  This is done at
servo level

6) dismiss to interpreter level.
	THE INTERPRETER SCHEDULER

	The interpreter scheduler is a set of routines used for
handling interpreter sprouting, termination, waiting, and scheduling,
and for on-monitor enabling and disabling.  The code "↑" means
switch to high priority (above any on-monitor); the code "↓" means
return to previous priority.

RCLASS ONID (INTEGER STATUS, OPC; RPTR (ONID) NEXT);
	COMMENT:  STATUS holds the Kill and Enable bits.
	OPC is the On-program counter.
	NEXT is used for chaining of ons;

RCLASS PROCESSID (INTEGER PC, DEPENDENTS, WAITTYPE;  
	RPTR(PROCESSID) NEXT, MOTHER; RPTR(ONID) RUNONS, WAITONS);
	COMMENT:  PC=program counter.  DEPENDENTS=count.
	WAITTYPE=0 for run, 1 for dependent wait, 2 for event wait.
	NEXT used for queuing.  MOTHER points to mother.
	RUNONS is list of dependent on-monitors.
	WAITONS is list of dependent on-monitors active only during wait;

RCLASS QUEUE (RPTR(PROCESSID) HEAD, TAIL);
RPTR (PROCESSID) CURRENT;
RPTR(QUEUE) RUNQUEUE;
DEFINE ENABLE = "'1";
DEFINE KILL = "'2";

PROCEDURE INITIALIZE;
	BEGIN
	QUEUE:HEAD(RUNQUEUE) ← NEW_RECORD (PROCESSID);
	FOREACH ON-MONITOR DO
		BEGIN
		X ← NEW_RECORD (ONID);
		ONID:NEXT(X) ← RNULL;
		ONID:STATUS(X) ← 0;
		ONID:OPC(X) ← OPC;
		END;
	END;

PROCEDURE ENQUEUE(RPTR(QUEUE) WHERE; RPTR(PROCESSID) NEW);
	BEGIN
	COMMENT:  Puts a process on a queue.  QUEUE tells which
		queue.  NEW is the process id;
	QUEUE:TAIL(WHERE) ← PROCESSID:NEXT(QUEUE:TAIL(WHERE)) ← NEW;
	PROCESSID:NEXT(QUEUE:TAIL(WHERE)) ← RNULL;
	END;

RPTR(PROCESSID) PROCEDURE DEQUEUE (RPTR(QUEUE) WHERE);
	BEGIN
	COMMENT:  Returns head of queue, which is removed;
	RPTR(PROCESSID) ANSWER;
	IF QUEUE:HEAD(WHERE) = QUEUE:TAIL(WHERE) 
	THEN	RETURN(RNULL);  COMMENT:  Empty queue;
	ANSWER ← PROCESSID:NEXT(QUEUE:HEAD(WHERE));
	IF (PROCESSID:NEXT(QUEUE:HEAD(WHERE)) ← PROCESSID:NEXT(ANSWER)) = RNULL
	THEN	QUEUE:TAIL(WHERE) ← QUEUE:HEAD(WHERE);
	RETURN(ANSWER);
	END;

PROCEDURE SPROUT (IPC);
	BEGIN
	COMMENT: IPC is the interpreter program counter.
	The effect is to put the new interpreter in the run-queue;
	RPTR (PROCESSID) NEW;
	↑;
	NEW ← NEW_RECORD (PROCESSID);
	PROCESSID:PC(NEW) ← IPC;
	PROCESSID:DEPENDENTS(NEW) ← 0;
	PROCESSID:WAITTYPE(NEW) ← 0;
	PROCESSID:MOTHER(NEW) ← CURRENT;
	PROCESSID:DEPENDENTS(CURRENT) ← PROCESSID:DEPENDENTS(CURRENT) + 1
	ENQUEUE(RUNQUEUE,NEW);
	↓;
	END;

PROCEDURE TERMINATE;
	BEGIN  COMMENT:  Terminates the caller;
	RPTR(PROCESSID) MOM;
	RPTR(ONID) VICTIM, OLD;
	INTEGER TEMP;
	↑;
	IF PROCESSID:DEPENDENTS(CURRENT) ≠ 0
	THEN 	BEGIN  COMMENT:  This should never happen;
		ERROR("ACTIVE PROCESS DEPENDS ON BLOCK BEING EXITED");
		WAIT;
		END;
	MOM ← PROCESSID:MOTHER(CURRENT);
	TEMP ← PROCESSID:DEPENDENTS(MOM) ← PROCESSID:DEPENENTS(MOM) - 1;
	IF PROCESSID:WAITTYPE(MOM)=1 AND TEMP=0
	THEN	BEGIN  COMMENT:  Must awaken mom;
		VICTIM ← PROCESSID:WAITONS(MOM);
		PROCESSID:WAITONS(MOM) ← RNULL;
		WHILE VICTIM ≠ RNULL DO
			BEGIN  COMMENT:  Kill mom's wait ons;
			DISABLE(VICTIM);
			OLD ← VICTIM;
			VICTIM ← ONID:NEXT(VICTIM);
			ONID:NEXT(OLD) ← RNULL;
			END;
		PROCESSID:WAITTYPE(MOM) ← 0;
		ENQUEUE(RUNQUEUE,MOM);
		END;
	VICTIM ← PROCESSID:RUNONS(CURRENT);
	PROCESSID:RUNONS(CURRENT) ← RNULL;
	WHILE VICTIM ≠ RNULL DO
		BEGIN  COMMENT:  Kill current's run ons;
		DISABLE(VICTIM);
		OLD ← VICTIM;
		VICTIM ← ONID:NEXT(VICTIM);
		ONID:NEXT(OLD) ← RNULL;
		END;
	CURRENT ← RNULL;  COMMENT:  explicit deallocate?;
	↓;
	JRST RESCHEDULE;
	END;

PROCEDURE WAIT;
	BEGIN  COMMENT: Caller wishes to wait until all descendents have dismissed;
	RPTR(ONID) DEB;
	↑;
	IF PROCESSID:DEPENDENTS(CURRENT) ≠ 0
	THEN	BEGIN  COMMENT:  Must wait;
		PROCESSID:PC(CURRENT) ← <RETURN ADDRESS>;
		PROCESSID:WAITTYPE(CURRENT) ← 1;
		DEB ← PROCESSID:WAITONS(CURRENT);
		WHILE DEB ≠ RNULL DO
			BEGIN  COMMENT:  Enable all wait ons;
			IF ONID:STATUS(DEB) LAND ENABLE = 0
			THEN	BEGIN
				ONID:STATUS(DEB) ← ONID:STATUS(DEB) LAND ¬KILL;
				PUSHJ (ONID:OPC(DEB));
				END;
			DEB ← NEXT(DEB);
			END;
		↓;
		JRST RESCHEDULE;
		END
	ELSE ↓;
	END;

PROCEDURE RUN_ENABLE (RPTR (ONID) MON);
	BEGIN  COMMENT:  Wish to enable a run on monitor;
	↑;
	IF ONID:STATUS(MON) LAND ENABLE ≠ 0
	THEN	BEGIN ↓; RETURN END;  COMMENT:  Already going;
	ONID:STATUS(MON) ← ONID:STATUS(MON) LAND ¬KILL;
	IF ONID:NEXT(MON) = RNULL 
	THEN	BEGIN  COMMENT:  Add this run on to list for Current;
		ONID:NEXT(MON) ← PROCESSID:RUNONS(CURRENT);
		PROCESSID:RUNONS(CURRENT) ← ONID;
		END;
	PUSHJ (ONID:OPC(MON));
	↓;
	END;

PROCEDURE WAIT_ENABLE (RPTR (ONID) MON);
	BEGIN  COMMENT:  Wish to set up a wait on monitor;
	↑;
	IF ONID:STATUS(MON) LAND ENABLE ≠ 0
	THEN	BEGIN ↓; RETURN END;  COMMENT:  Already going;
	IF ONID:NEXT(MON) = RNULL 
	THEN	BEGIN  COMMENT:  Add this wait on to list for Current;
		ONID:NEXT(MON) ← PROCESSID:WAITONS(CURRENT);
		PROCESSID:WAITONS(CURRENT) ← ONID;
		END;
	↓;
	END;

PROCEDURE DISABLE (RPTR(ONID) MON);
	BEGIN  
	ONID:STATUS(MON) ← KILL;
	END;

PROCEDURE RESCHEDULE;
	BEGIN
	↑;
	IF CURRENT = RNULL 
	THEN 	BEGIN
		WHILE RUNQUEUE = RNULL DO BEGIN ↓; ↑; END;
		CURRENT ← DEQUEUE(RUNQUEUE);
		PUSH NAME(CURRENT);
		PUSH IPC(CURRENT);
		↓;
		PUSHJ INTERPRETER;
		END;
	ELSE	↓;
	END;

DEPROACHES  now in memo
SYSTEM USER FEATURES

	The HAL  system is  intended to  be a  flexible tool for  the
planning  of  complex  assembly tasks  by  a  skilled operator.  This
planning has  several  phases: initial  preparation of  the  program,
removing syntactic errors  from the source code,   trying the program
out,   and   fixing   discoved   bugs   until   the   program   works
satisfactorilly.   The  final  stage is  the  production run  of  the
program,  which can occur  in a  basically unsupervised  mode. During
execution, however, it is still possible to interrupt the machine and
find out exactly where it  is in the plan and debug  it further. This
is  useful for  patching a program  which over  the course of  a long
execution begins to "drift" from reality.
	Thus, the  user features can  be divided  roughly into  these
parts:
	PROGRAM FORMULATION
	It is  hoped that the  HAL language described in  some detail
earlier  provides a  clear and  complete system  in which  to express
those  manipulations  necessary  for  the  correct  execution  of  an
assembly task.  The structured concept of statement, made powerful by
the relatively unstructured  concept of the  on-monitor, should  make
writing in HAL relatively easy.  
	One other way in which HAL can  assist the programmer is that
she can  have it read the current location of  an arm and to use that
frame as a constant in her program.  This makes programming  by doing
possible.  One way to put together a simple program is merely to move
the arm  manually to the different locations desired, have the system
remember  those  locations,  and  then  type  in  appropriate  motion
commands between these points.

	PROGRAM COMPILATION
	The supervisor is the key to this and the following features;
it  allows the user  to oversee the  progress of her  program and fix
errors as  they  arise.   There  is  a simple  "supervisor  language"
intended for communication with the HAL system.  Some of its commands
are  demonstrated in  the sample  dialog given  earlier.  One  of the
commands causes compilation to begin; the parser is  directed to read
some file.  One option  is to have console input itself used to enter
the source code; this is especially  useful in causing the arm to  do
something immediately. When the parser finds a  syntax error, it will
give  an  error  message, and  several  options  will  in general  be
available.  These include  aborting the compilation, skipping to  the
ebd of the  current statement, editing the line with  the system line
editor  (after  which  the  entire  statement  will  be reparsed,  if
possible), and  temporarily switching  to a  text editor  to fix  the
problem (after which the entire program must be reparsed).  
	The expander can also find errors; these are usually semantic
errors, like generating  a move  to a point  with undefined  planning
value, not supplying enough information to a high-level primitive, or
attempting to move the same arm simultaneously in two blocks of code.
In those cases where the problem is one of  insufficient information,
the expander will  prompt for more, and, if possible,  continue.  The
user may decide not to supply that information, and in that case, the
offending statement is  flushed.   Some errors are  so drastic as  to
require complete  recompilation; the user is always  given the option
of switching to a text editor for major modifications.
	There is  a limited  number of  errors which  the  trajectory
calculator is capable  of discovering.  These mostly  involve motions
beyond the  capability of the manipulators involved.   Options to the
user include making the  best legal trajectory possible, causing  the
trajectory to be slowed down, and putting in a null trajectory.

	PROGRAM EXECUTION
	After a  program has been compiled,  it resides on disk  as a
load module.   Any number of load modules can be loaded together; the
principal restriction is that each of them be a  "top level" program.
As mentioned earlier, the loader will resolve calls between the large
(planning) computer  and the  small  (execution) computer  for  those
functions  which  the  user has  decided  require  the  computational
ability found only on the large computer.
	Execution  is initiated by another  supervisor command issued
by the user.  While the  mini is executing the program, the user  can
cause an interruption  and examine values within  the runtime system,
and  modify them if she  wishes.  It is also  possible to examine the
code generated by the compiler and modify it, but this is most likely
only  of interest to  system programmers.   Sizeable  patches require
recompilation.
	Sometimes hardware difficulties will cause abrupt termination
of  the   program;  these  often   are  due  to   runtime  trajectory
modifications  overstraining the  hardware.   After issuing  an error
message to the user,  the system behaves just  as it would should  it
have been interrupted manually.
	It is possible, during one of these "breaks", to request that
the  entire world  be saved.   This causes  all runtime  values to be
written out  into a  safe place,  along with  the current  attachment
structure and  the current program counters.   There are several uses
for this  feature:  it allows  the  debugging  of the  task  to  stop
temporarily and  to be resumed  later.  More  important, it  plants a
"safe point" in the  code, so that if an error should occur later, it
is possible to back up the program to a point at which everything was
still working.
	Programs  which   have  been   completely  debugged   can  be
"unloaded",  that is, saved in a dump  file for execution any time in
the future.